package com.smart.sso.server.controller;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.smart.mvc.model.Result;
import com.smart.mvc.model.ResultCode;
import com.smart.mvc.util.StringUtils;
import com.smart.mvc.validator.Validator;
import com.smart.mvc.validator.annotation.ValidateParam;
import com.smart.sso.client.SsoFilter;
import com.smart.sso.server.captcha.CaptchaHelper;
import com.smart.sso.server.common.LoginUser;
import com.smart.sso.server.common.TokenManager;
import com.smart.sso.server.controller.common.BaseController;
import com.smart.sso.server.log.SystemControllerLog;
import com.smart.sso.server.model.User;
import com.smart.sso.server.model.UserRole;
import com.smart.sso.server.provider.IdProvider;
import com.smart.sso.server.provider.PasswordProvider;
import com.smart.sso.server.service.UserRoleService;
import com.smart.sso.server.service.UserService;
import com.smart.sso.server.util.CookieUtils;
import com.smart.sso.server.util.OperationUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

/**
 * @author Joe
 */
@Api(tags = "单点登录管理")
@Controller
@RequestMapping("/login")
public class LoginController extends BaseController{
	
	// 登录页
	private static final String LOGIN_PATH = "/login";

	@Resource
	private TokenManager tokenManager;
	@Resource
	private UserService userService;
	@Resource
	private UserRoleService userRoleService;

	@ApiOperation("登录页")
	@RequestMapping(method = RequestMethod.GET)
	public String login(
			@ApiParam(value = "返回链接", required = true) @ValidateParam({ Validator.NOT_BLANK }) String backUrl,
			HttpServletRequest request) {
		String token = CookieUtils.getCookie(request, TokenManager.TOKEN);
		if (StringUtils.isNotBlank(token) && tokenManager.validate(token) != null) {
			return "redirect:" + authBackUrl(backUrl, token);
		}
		else {
			return goLoginPath(backUrl, request);	//跳转到登陆页面
		}
	}

	@ApiOperation("登录提交")
	@RequestMapping(method = RequestMethod.POST)
	@SystemControllerLog(operationId = OperationUtils.operation_login ,description = "登陆系统")
	public String login(
			@ApiParam(value = "返回链接", required = true) @ValidateParam({ Validator.NOT_BLANK }) String backUrl,
			@ApiParam(value = "登录名", required = true) @ValidateParam({ Validator.NOT_BLANK }) String account,
			@ApiParam(value = "密码", required = true) @ValidateParam({ Validator.NOT_BLANK }) String password,
			@ApiParam(value = "验证码", required = true) @ValidateParam({ Validator.NOT_BLANK }) String captcha,
			HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
		if (!CaptchaHelper.validate(request, captcha)) {	//验证session中的captcha与用户输入的captcha是否一致。
			request.setAttribute("errorMessage", "验证码不正确");
			return goLoginPath(backUrl, request);	//返回到登录页面
		}
//		Result result = userService.login(getIpAddr(request), account, PasswordProvider.encrypt(password), request);
		Result result = Result.createSuccessResult();
		result.setCode(ResultCode.SUCCESS);
		User tuser = new User();
		tuser.setAccount("admin");
		tuser.setId(1);
		result.setData(tuser);
		if (!result.getCode().equals(ResultCode.SUCCESS)) {
			request.setAttribute("errorMessage", result.getMessage());
			return goLoginPath(backUrl, request);
		}
		else {
			User user = (User) result.getData();
			LoginUser loginUser = new LoginUser(user.getId(), user.getAccount());
			String token = CookieUtils.getCookie(request, TokenManager.TOKEN);
			request.getSession().setAttribute("CURRENT_USER", loginUser);	//保存当前登陆用户
			request.getSession().setAttribute("NODE_KEY", "MASTER");
//			List<UserRole> userRoles = userRoleService.findByUserRoleId(user.getId(), null);
//			Integer roleId = userRoles.get(0).getRoleId();
//			request.getSession().setAttribute("CURRENT_ROLE", roleId);
			if (StringUtils.isBlank(token) || tokenManager.validate(token) == null) {// 没有登录的情况
				token = createToken(loginUser);	//生成token
				addTokenInCookie(token, request, response);//将token存入cookie并返回给客户端
			}

			// 跳转到原请求，即最初的请求
			backUrl = URLDecoder.decode(backUrl, "utf-8");
			return "redirect:" + authBackUrl(backUrl, token);
		}
	}
	
	/**
	 * 跳转到登陆页面
	 * @param backUrl
	 * @param request
	 * @return
	 */
	private String goLoginPath(String backUrl, HttpServletRequest request) {
		request.setAttribute("backUrl", backUrl);
		return LOGIN_PATH;	//\smart\smart-mvc\src\main\resources\spring-mvc.xml配置suffix为.jsp。所以返回页面login.jsp
	}

	private String authBackUrl(String backUrl, String token) {
		StringBuilder sbf = new StringBuilder(backUrl);
		if (backUrl.indexOf("?") > 0) {
			sbf.append("&");
		}
		else {
			sbf.append("?");
		}
		sbf.append(SsoFilter.SSO_TOKEN_NAME).append("=").append(token);//将token加在请求后面
		return sbf.toString();
	}

	/**
	 * 生成token
	 * @param loginUser
	 * @return
	 */
	private String createToken(LoginUser loginUser) {
		// 生成token
		String token = IdProvider.createUUIDId();

		// 缓存中添加token对应User
		tokenManager.addToken(token, loginUser);
		return token;
	}
	
	/**
	 * 将token存入cookie，并返回给客户端
	 * @param token
	 * @param request
	 * @param response
	 */
	private void addTokenInCookie(String token, HttpServletRequest request, HttpServletResponse response) {
		// Cookie添加token
		Cookie cookie = new Cookie(TokenManager.TOKEN, token);	//实例化Cookie对象，传入cooke名称和cookie的值
		/* 设置cookie的有效路径，比如把cookie的有效路径设置为"/xdp"，那么浏览器访问"xdp"目录下的web资源时，
		 * 都会带上cookie，再比如把cookie的有效路径设置为"/xdp/gacl"，那么浏览器只有在访问"xdp"目录下的
		 * "gacl"这个目录里面的web资源时才会带上cookie一起访问，而当访问"xdp"目录下的web资源时，浏览器是
		 * 不带cookie的*/
		cookie.setPath("/");
		if ("https".equals(request.getScheme())) {	//request.getScheme() 返回当前链接使用的协议；比如，一般应用返回http;SSL返回https;
			cookie.setSecure(true);	//指示浏览器是否只使用安全协议（如HTTPS或SSL）发送Cookie。
		}
		cookie.setHttpOnly(true);	//在支持HttpOnly cookies的浏览器中（IE6+，FF3.0+），如果在Cookie中设置了"HttpOnly"属性，那么通过JavaScript脚本将无法读取到Cookie信息，这样能有效的防止XSS攻击，让网站应用更加安全。
		response.addCookie(cookie);	//向客户端加入Cookie
	}
}